﻿using CodeGenerator.Common;
using CodeGenerator.Models;
using Force.DeepCloner;
using ICSharpCode.SharpZipLib.Zip;
using SqlSugar;
using System.Data;

namespace CodeGenerator.Data
{
    public class Generator
    {
        readonly string _conn;
        readonly SqlSugar.DbType _dbType;
        readonly string _outBasePath, _outPath, _nameSpace;

        /// <summary>
        /// 代码生成构造函数
        /// </summary>
        /// <param name="conn"></param>
        /// <param name="dbType"></param>
        /// <param name="userid"></param>
        public Generator(string conn, string dbType, string nameSpace, int userid)
        {
            _conn = conn;
            _dbType = (SqlSugar.DbType)Enum.Parse(typeof(SqlSugar.DbType), dbType);
            _outBasePath = $"{AppDomain.CurrentDomain.BaseDirectory}UserCodes\\{userid}_CodeGenerator\\";
            if (Directory.Exists(_outBasePath))
            {
                Directory.Delete(_outBasePath, true);
            }
            _outPath = $"{AppDomain.CurrentDomain.BaseDirectory}UserCodes\\{userid}_code.zip";
            if (Directory.Exists(_outPath))
            {
                Directory.Delete(_outPath, true);
            }
            _nameSpace = nameSpace;
        }

        public List<DbTableInfo> GetTables(List<string> findTable = null, bool ignoreCase = true)
        {
            SqlSugarClient sqlSugar = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = _conn,
                DbType = _dbType,
                InitKeyType = InitKeyType.Attribute,
                IsAutoCloseConnection = true
            });
            List<DbTableInfo> tables = sqlSugar.DbMaintenance.GetTableInfoList(false);
            if (findTable != null)
            {
                tables = tables.FindAll(s =>
                {
                    if (ignoreCase)
                    {
                        return findTable.Exists(f => f.ToLower() == s.Name.ToLower());
                    }
                    else
                    {
                        return findTable.Exists(f => f == s.Name);
                    }
                });
            }
            return tables;
        }

        public List<DbColumnInfo> GetColumns(string table)
        {
            SqlSugarClient sqlSugar = new SqlSugarClient(new ConnectionConfig()
            {
                ConnectionString = _conn,
                DbType = _dbType,
                InitKeyType = InitKeyType.Attribute,
                IsAutoCloseConnection = true
            });
            List<DbColumnInfo> columns = sqlSugar.DbMaintenance.GetColumnInfosByTableName(table, false);
            DataTable dt = sqlSugar.Ado.GetDataTable($"select * from {table} where 1=2");
            foreach (DbColumnInfo info in columns)
            {
                foreach (DataColumn column in dt.Columns)
                {
                    if (info.DbColumnName.ToLower() == column.ColumnName.ToLower())
                    {
                        info.PropertyType = column.DataType;
                    }
                }
            }
            return columns;
        }

        /// <summary>
        /// 生成代码
        /// </summary>
        public string GeneratorCode(List<string> tableNames, List<string> generatorType, bool IgnoreNull = true, bool GenBase = false)
        {
            List<DbTableInfo> tables = GetTables(tableNames);
            foreach (DbTableInfo table in tables)
            {
                List<DbColumnInfo> columns = GetColumns(table.Name);

                List<GeneratorFieldModel> fields = new List<GeneratorFieldModel>();
                foreach (var column in columns)
                {
                    fields.Add(new GeneratorFieldModel
                    {
                        FieldDesc = column.ColumnDescription,
                        SystemType = column.PropertyType,
                        Type = column.PropertyType.Name,
                        FieldName = column.DbColumnName,
                        DefaultValue = column.DefaultValue,
                        IsPrimaryKey = column.IsPrimarykey,
                        IsIdentity = column.IsIdentity,
                        IsNullable = column.IsNullable,
                        MaxLength = column.Length,
                        IgnoreInserFileds = new string[] { "SysDeleteTime" }
                    });
                }
                GeneratorModel generatorModel = new GeneratorModel
                {
                    NameSpace = _nameSpace,
                    TableName = table.Name,
                    TableDesc = table.Description,
                    FieldsModels = fields
                };
                if (generatorType.Contains("Entity")) GeneratorEntity(generatorModel.DeepClone());
                if (generatorType.Contains("DtoInput")) GeneratorDtoInput(generatorModel.DeepClone(), IgnoreNull, GenBase);
                if (generatorType.Contains("DtoOutput")) GeneratorDtoOutput(generatorModel.DeepClone(), IgnoreNull, GenBase);
                if (generatorType.Contains("IService")) GeneratorIService(generatorModel.DeepClone()    , GenBase);
                if (generatorType.Contains("Service")) GeneratorService(generatorModel.DeepClone(), GenBase);
                if (generatorType.Contains("Repository")) GeneratorRepository(generatorModel.DeepClone(), GenBase);
                if (generatorType.Contains("Controller")) GeneratorController(generatorModel.DeepClone());
                if (generatorType.Contains("Vue")) GeneratorVue(generatorModel.DeepClone());
            }
            using ZipOutputStream outStream = new ZipOutputStream(File.Create(_outPath));
            ZipUtil.ZipDir(_outBasePath, outStream);
            return _outPath;
        }

        /// <summary>
        /// 生成Entity代码
        /// </summary>
        /// <param name="generatorModel"></param>
        public void GeneratorEntity(GeneratorModel generatorModel)
        {
            generatorModel.FieldsModels.ForEach(f =>
            {
                if (f.Type.ToLower().StartsWith("int") || f.Type.ToLower() == "long" || f.Type.ToLower() == "decimal")
                {
                    f.IsNullable = false;
                }
            });

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\ModelTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Entity\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}.cs";

            string content = template.
                Replace("@NameSpace", generatorModel.NameSpace + ".Entity").
                Replace("@ModelDesc", generatorModel.TableName + ":数据库映射类").
                Replace("@TableDesc", generatorModel.TableDesc).
                Replace("@TableNameHump", generatorModel.TableNameHump).
                Replace("@TableName", $"[SugarTable(\"{generatorModel.TableName}\")]").
                Replace("@Fields", generatorModel.Fields);

            File.WriteAllText(outPath, content);
        }

        /// <summary>
        /// 生成数据传输Input类代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorDtoInput(GeneratorModel generatorModel, bool IgnoreNull = true, bool GenBase = false)
        {
            generatorModel.FieldsModels.ForEach(f =>
            {
                f.IsAddAttribute = false;
                if (IgnoreNull)
                {
                    f.IsNullable = false;
                }
                if (f.Type.ToLower() == "string" || f.Type == nameof(DateTime))
                {
                    //Input类需要String可为Null才能接收数量不匹配参数
                    f.IsNullable = true;
                }
            });
            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\ModelTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Model\\Dtos\\Input\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}_IN.cs";

            string content = template.
               Replace("@NameSpace", generatorModel.NameSpace + ".Model.Dtos.Input").
               Replace("@ModelDesc", generatorModel.TableName + ":数据传输Input类").
               Replace("@TableDesc", generatorModel.TableDesc).
               Replace("@TableNameHump", generatorModel.TableNameHump + "_IN: BaseInput").
               Replace("@TableName", "").
               Replace("@Fields", generatorModel.Fields).
               Replace("using SqlSugar;", "");

            File.WriteAllText(outPath, content);

            if (GenBase)
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\BaseInputTemplate.txt";
                string baseOutPath = _outBasePath + "Model\\Dtos\\BaseInput.cs";
                string baseContent = File.ReadAllText(basePath);
                baseContent = baseContent.Replace("@NameSpace", generatorModel.NameSpace + ".Model.Dtos");
                File.WriteAllText(baseOutPath, baseContent);
            }
        }

        /// <summary>
        /// 生成数据传输Output类代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorDtoOutput(GeneratorModel generatorModel, bool IgnoreNull = true, bool GenBase = false)
        {
            generatorModel.FieldsModels.ForEach(f =>
            {
                f.IsAddAttribute = false;
                if (IgnoreNull)
                {
                    f.IsNullable = false;
                }
                if (f.Type == nameof(DateTime))
                {
                    //Output类设置DateTime类型可以null
                    f.IsNullable = true;
                }
            });

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\ModelTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Model\\Dtos\\Output\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}_OUT.cs";

            string content = template.
               Replace("@NameSpace", generatorModel.NameSpace + ".Model.Dtos.Output").
               Replace("@ModelDesc", generatorModel.TableName + ":数据传输Output类").
               Replace("@TableDesc", generatorModel.TableDesc).
               Replace("@TableNameHump", generatorModel.TableNameHump + "_OUT").
               Replace("@TableName", "").
               Replace("@Fields", generatorModel.Fields).
               Replace("using SqlSugar;", "");

            File.WriteAllText(outPath, content);
            if (GenBase)
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\PageOutputTemplate.txt";
                string baseOutPath = _outBasePath + "Model\\Dtos\\PageOutput.cs";
                string baseContent = File.ReadAllText(basePath);
                baseContent = baseContent.Replace("@NameSpace", generatorModel.NameSpace + ".Model.Dtos");
                File.WriteAllText(baseOutPath, baseContent);
            }
        }
        /// <summary>
        /// 生成IService代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorIService(GeneratorModel generatorModel, bool GenBase = false)
        {
            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\IServiceTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Service\\IService\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"I{generatorModel.TableNameHump}Service.cs";

            string content = template.
                Replace("@UsingName", generatorModel.NameSpace).
                Replace("@NameSpace", generatorModel.NameSpace + ".Service.IService").
                Replace("@TableName", generatorModel.TableNameHump);

            File.WriteAllText(outPath, content);

            if (GenBase)
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\IBaseServiceTemplate.txt";
                string baseOutPath = _outBasePath + "Service\\IBaseService.cs";
                string baseContent = File.ReadAllText(basePath);
                baseContent = baseContent.Replace("@NameSpace", generatorModel.NameSpace + ".Service").
                    Replace("@UsingName", generatorModel.NameSpace);
                File.WriteAllText(baseOutPath, baseContent);
            }
        }


        /// <summary>
        /// 生成Service代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorService(GeneratorModel generatorModel, bool GenBase = false)
        {

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\ServiceTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Service\\Service\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}Service.cs";

            string content = template.
                Replace("@UsingName", generatorModel.NameSpace).
                Replace("@NameSpace", generatorModel.NameSpace + ".Service.Service").
                 Replace("@FLTableName", generatorModel.TableNameHump.FirstCharToLower()).
                Replace("@TableName", generatorModel.TableNameHump);

            //增加部门条件
            if (generatorModel.FieldsModels.Exists(s => s.FieldName.ToLower() == "deptid"))
            {
                content = content.Replace("@DeptParam", @"var (dataRang, permissions) = GetUserPermission();
            switch (dataRang)
            {
                case DataRang.All:
                    break;
                case DataRang.Dept:
                    exp.And(t => t.DeptId == Token.UserDept);
                    break;
                case DataRang.DeptAndBelow:
                    exp.And(t => GetRecursiveDept().Contains(t.DeptId));
                    break;
                case DataRang.Self:
                    exp.And(t => t.SysCreateUser == Token.UserId);
                    break;
                case DataRang.Custom:
                    exp.And(t => permissions.Contains(t.DeptId));
                    break;
            }");
            }
            else
            {
                content = content.Replace("@DeptParam", "");
            }

            File.WriteAllText(outPath, content);
            if (GenBase)
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\BaseServiceTemplate.txt";
                string baseOutPath = _outBasePath + "Service\\BaseService.cs";
                string baseContent = File.ReadAllText(basePath);
                baseContent = baseContent.Replace("@NameSpace", generatorModel.NameSpace + ".Service").
                    Replace("@UsingName", generatorModel.NameSpace);
                File.WriteAllText(baseOutPath, baseContent);
            }
        }

        /// <summary>
        /// 生成Repository代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorRepository(GeneratorModel generatorModel, bool GenBase = false)
        {

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\RepositoryTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Repository\\Repository\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}Repository.cs";

            string content = template.
                Replace("@UsingName", generatorModel.NameSpace).
                Replace("@NameSpace", generatorModel.NameSpace + ".Repository.Repository").
                Replace("@TableName", generatorModel.TableNameHump);

            File.WriteAllText(outPath, content);

            if (GenBase)
            {
                string basePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\BaseRepositoryTemplate.txt";
                string baseOutPath = _outBasePath + "Repository\\BaseRepository.cs";
                string baseContent = File.ReadAllText(basePath);
                baseContent = baseContent.Replace("@NameSpace", generatorModel.NameSpace + ".Repository").
                    Replace("@UsingName", generatorModel.NameSpace);
                File.WriteAllText(baseOutPath, baseContent);
            }
        }

        /// <summary>
        /// 生成Controller代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorController(GeneratorModel generatorModel)
        {

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\ControllerTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + "Controller\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += $"{generatorModel.TableNameHump}Controller.cs";

            string content = template.
                Replace("@UsingName", generatorModel.NameSpace).
                Replace("@NameSpace", generatorModel.NameSpace + ".WebApi.Controllers").
                 Replace("@FLTableName", generatorModel.TableNameHump.FirstCharToLower()).
                Replace("@TableName", generatorModel.TableNameHump);

            File.WriteAllText(outPath, content);
        }

        /// <summary>
        /// 生成Vue代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorVue(GeneratorModel generatorModel)
        {
            GeneratorVueIndex(generatorModel);
            GeneratorEdit(generatorModel);
        }

        /// <summary>
        /// 生成Vue-Index代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorVueIndex(GeneratorModel generatorModel)
        {
            string[] ignoreColumns = new string[] { "SysCreateUser", "SysCreateTime", "SysUpdateTime", "SysDeleteUser", "SysDeleteTime", "SysIsDelete", "SysUpdateUser", "DeptId" };

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\VueIndexTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + $"Vue\\{generatorModel.TableNameRemoveT}\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += "index.vue";

            List<GeneratorFieldModel> list = generatorModel.FieldsModels;
            string tableData = "";
            foreach (var field in list)
            {
                if (field.IsIdentity && field.IsPrimaryKey)
                {
                    continue;
                }
                if (field.MaxLength > 200)
                {
                    continue;
                }
                if (ignoreColumns.Contains(field.FieldNameHump))
                {
                    continue;
                }
                tableData += $"<el-table-column prop=\"{field.FieldNameHump}\" label=\"{field.FieldDesc}\"  ></el-table-column>\r\n";
            }

            string content = template.
             Replace("@TableName", generatorModel.TableNameHump).
             Replace("@TableData", tableData);

            File.WriteAllText(outPath, content);
        }

        /// <summary>
        /// 生成Vue-Edit代码
        /// </summary>
        /// <param name="generatorModel"></param>
        private void GeneratorEdit(GeneratorModel generatorModel)
        {
            string[] ignoreColumns = new string[] { "SysCreateUser", "SysCreateTime", "SysUpdateTime", "SysDeleteUser", "SysDeleteTime", "SysIsDelete", "SysUpdateUser", "DeptId" };

            string templatePath = AppDomain.CurrentDomain.BaseDirectory + "Templates\\VueEditTemplate.txt";
            string template = File.ReadAllText(templatePath);

            string outPath = _outBasePath + $"Vue\\{generatorModel.TableNameRemoveT}\\";
            if (!Directory.Exists(outPath))
            {
                Directory.CreateDirectory(outPath);
            }

            outPath += "edit.vue";

            List<GeneratorFieldModel> list = generatorModel.FieldsModels;
            string formData = "", formRules = "", filedData = "";
            foreach (var field in list)
            {
                if (field.IsIdentity && field.IsPrimaryKey)
                {
                    continue;
                }
                if (ignoreColumns.Contains(field.FieldNameHump))
                {
                    continue;
                }
                formData += $@"<el-col :xs=""24"" :sm=""12"" :md=""12"" :lg=""12"" :xl=""12"" class=""mb20"">
					<el-form-item label=""{field.FieldDesc}"" prop=""{field.FieldNameHump}"">
						<el-input v-model=""formData.{field.FieldNameHump}"" clearable></el-input>
					</el-form-item>
				</el-col>
";
                if (!field.IsNullable)
                {
                    formRules += $@"{field.FieldNameHump}: [{{required: true, message: '{field.FieldDesc}不可为空', trigger: 'blur' }}],
";
                }
                filedData += $@"{field.FieldNameHump}: {GetDefaultValue(field.SystemType)},
";
            }
            string content = template.
             Replace("@TableName", generatorModel.TableNameHump).
             Replace("@FormData", formData).
             Replace("@RulesData", formRules).
             Replace("@FiledData", filedData);

            File.WriteAllText(outPath, content);
        }


        string GetDefaultValue(Type type)
        {
            // 如果类型是值类型，则获取其默认值  
            if (type.IsValueType)
            {
                // 对于值类型，可以使用Type的默认值，或者通过反射获取Default属性 
                object value = type.IsEnum ? Enum.ToObject(type, 0) : Activator.CreateInstance(type);
                if (Convert.ToString(value) == "")
                {
                    return "''";
                }
                return value.ToString().ToLower();
            }
            // 如果类型是引用类型，则默认值是null  
            else
            {
                return "''";
            }
        }
    }
}
